//-------------------------------------------------------------------------------------------------
// Copyright (c) Bradford W. Mott and Flare Contributors
// North Carolina State University, Department of Computer Science
// The IntelliMedia Group
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//-------------------------------------------------------------------------------------------------

namespace Flare.Events
{
    /// <summary>
    /// The Event class is a base class for event objects, which are passed to event listeners.
    /// </summary>
    public class Event
    {
        /// <summary>
        /// Gets the event type
        /// </summary>
        public string type { get; 
            /* \cond */ private set; /* \endcond */ }

        /// <summary>
        /// Gets whether the event bubbles or not
        /// </summary>
        public bool bubbles { get; 
            /* \cond */ private set; /* \endcond */ }

        /// <summary>
        /// Gets whether the event behavior can be prevented or not
        /// </summary>
        public bool cancelable { get; 
            /* \cond */ private set; /* \endcond */ }

        /// <summary>
        /// Gets the object that is actively processing the event with an event listener
        /// </summary>
        public object currentTarget { get; 
            /* \cond */ internal set; /* \endcond */ }

        /// <summary>
        /// Gets the current phase of the event
        /// </summary>
        public uint eventPhase { get; 
            /* \cond */ internal set; /* \endcond */ }

        /// <summary>
        /// Gets the object that is the event target
        /// </summary>
        public object target { get;
            /* \cond */ internal set; /* \endcond */ }

        // Indicates if stopImmediatePropagation has been called or not
        internal bool immediatePropagationStopped { get; set; }

        // Indicates if stopPropagation has been called or not
        internal bool propagationStopped { get; set; }

        // Indicates if preventDefault has been called or not
        internal bool defaultPrevented { get; set; }

        /// <summary>
        /// enterFrame event type is dispatched every time the playhead enters a new frame
        /// but before new display objects are constructed for the frame
        /// </summary>
        public const string ENTER_FRAME = "enterFrame";

        /// <summary>
        /// frameConstructed event type is dispatched every time the playhead enters a new
        /// frame and after new display objects are constructed for the frame
        /// </summary>
        public const string FRAME_CONSTRUCTED = "frameConstructed";

        /// <summary>
        /// exitFrame event type is dispatched at the end of each frame right before the
        /// frame is rendered
        /// </summary>
        public const string EXIT_FRAME = "exitFrame";

        /// <summary>
        /// Create a new instance of the Event class.
        /// </summary>
        public Event(string type, bool bubbles = false, bool cancelable = false)
        {
            this.type = type;
            this.bubbles = bubbles;
            this.cancelable = cancelable;
            this.eventPhase = EventPhase.AT_TARGET;

            this.immediatePropagationStopped = false;
            this.propagationStopped = false;
            this.defaultPrevented = false;
        }

        /// <summary>
        /// Return a clone of the event.
        /// </summary>
        public virtual Event Clone()
        {
            Event clone = (Event)this.MemberwiseClone();

            this.immediatePropagationStopped = false;
            this.propagationStopped = false;
            this.defaultPrevented = false;

            return clone;
        }

        /// <summary>
        /// Returns true if the PreventDefault() method has been called on the event.
        /// </summary>
        public bool IsDefaultPrevented()
        {
            return this.defaultPrevented;
        }

        /// <summary>
        /// Cancels the event's default behavior, if possible.
        /// </summary>
        public void PreventDefault()
        {
            if (this.cancelable)
            {
                this.defaultPrevented = true;
            }
        }

        /// <summary>
        /// Stop processing any event listeners in the current node and any subsequent nodes.
        /// </summary>
        public void StopImmediatePropagation()
        {
            this.immediatePropagationStopped = true;
            this.propagationStopped = true;
        }

        /// <summary>
        /// Stop processing any event listeners in any subsequent nodes.
        /// </summary>
        public void StopPropagation()
        {
            this.propagationStopped = true;
        }

        public override string ToString()
        {
            return string.Format("[Event type={0} bubbles={1} cancelable={2} eventPhase={3}]",
                this.type, this.bubbles, this.cancelable, this.eventPhase);
        }
    }
}
